#pragma once

#include <string_view>
#include <vector>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <chrono>

#include "./object.h"
#include "./osd_types.h"

#include "../PMEMDevice.hpp"


namespace ceph_mock {
using namespace std;

/**
 * @note original Ceph uses small_vector<OSDOp, 2> here
 */
using osdc_opvec = vector<OSDOp>;


class Objecter {
public:
    struct op_target_t {
        object_t base_oid;

        /* ... */

        /**
         * @note the original Ceph impl uses this copy-construct
         */
        op_target_t(object_t oid) : base_oid(oid)
        { }
    };  /* struct op_target_t */

    class Op {
    public:
        op_target_t target;

        osdc_opvec ops;

        ceph_snapid_t snapid = CEPH_NOSNAP;
        double mtime;

        /* ... */

    public:
        Op(string_view oid, osdc_opvec &&ops)
            : target(oid), ops(std::move(ops))
        {
            mtime = std::chrono::duration_cast<std::chrono::duration<double>>(
                std::chrono::system_clock::now().time_since_epoch())
                .count();
        }
    };  /* class Op */

private:
    mutable std::shared_mutex rwlock;
public:
    std::unique_ptr<PMKV::PMEMDevice> rpmkv = nullptr;

public:
    void op_submit(Op *op)
    {
        std::shared_lock rl(rwlock);
        int result;
        _maybe_do_op_on_pmem(op, rl, result);
    }
    void _send_op_account(Op *op)
    { /*pass*/; }
    bool _maybe_do_op_on_pmem(Op *op, std::shared_lock<std::shared_mutex> &sul, int &result);
};  /* class Objecter */

}   /* namespace ceph_mock */
